package hist.mobilprogramming.tictactoeapplication;

/**
 * Handles a serial positions in matrix and to convertion between numeric and string 
 * representation. Start position in matrix is at first row and column element.
 * Could be 0,0 or 1,1 depending choosen start position. 
 * Next position is counted from first row from left to right, to last column and then below to next row.   
 * @author godtltro
 */
public class Matrix
{
	private int _rowDim;
	private int _columnDim;
	private int _upperBound = 0;
	private int _zeroASserialStartPosition = 0;
	private int _changeStartElement = 0;
	
	/**
	 * @param dim Dimension for a square matrix (m x m)
	 */
	public Matrix(int dim)
	{
		_rowDim = dim;  
		_columnDim = dim;
		_upperBound = dim * dim;
	}

	/**
	 * @param rowDim Size of row dimension
	 * @param columnDim Size of column dimension
	 */
	public Matrix(int rowDim, int columnDim)
	{
		_rowDim = rowDim;  
		_columnDim = columnDim;
		_upperBound = rowDim * columnDim;
	}

	public boolean equals(Object obj) 
	{ 
		if (obj instanceof Matrix)
		{
			Matrix matrix = (Matrix) obj;
			if (this._rowDim == matrix._rowDim && this._columnDim == matrix._columnDim)
			{
				return true;
			}
		}
		
		return false;
	}

	/**
	 * @param serialPosition
	 * @return Element based on a position from a matrix
	 */
	public SquareElement getElement(int serialPosition)
	{
		if (OutOfValidRange(serialPosition)) return null;
		
		int row = 1;
		int col = 1;
		if (serialPosition == 1)
			return new SquareElement(row, col);
		
		if (serialPosition % _columnDim == 0)
		{
			row = serialPosition / _columnDim;
			col = _columnDim;
			return new SquareElement(row, col); 
		}
		row = (serialPosition / _columnDim) + 1;
		col = GetColumnIndex(serialPosition, row);
		
		return new SquareElement(row, col);
		
	}

	private int GetColumnIndex(int serialPosition, int row)
	{
		int lastPos = row * _columnDim; 	
		int firstPos = lastPos - _columnDim + 1;	
										
		int colCounter = 1;
		for (int currenColPos = firstPos; currenColPos <= lastPos; currenColPos++)
		{			
			if (serialPosition == currenColPos)
			{
				return colCounter;
			}
			colCounter++;
		}

		return colCounter;
	}
	
	private boolean OutOfValidRange(int serialPosition)
	{
		if (_rowDim <= 0 || _columnDim <= 0)
			return true;
		
		if (serialPosition > _upperBound)
			return true;
		
		return false;
	}

	
	/**
	 * Convert string matrix elements to numeric positions
	 * @param inputList List of positions in a matrix. Each element must be string at the format (x,y)
	 * @return Return list of numeric values that are the equal serial position for the string elements.
	 */
	public Integer[] getSerialPositions(String[] inputList)
	{
		if (inputList == null) 
			return new Integer[0];
		
		Integer[] posList = new Integer[inputList.length];
		for (int index = 0; index < inputList.length; index++)
		{
			posList[index] = calculatePosition(inputList[index]);
		}
		
		return posList;
	}

	/**
	 * @param value String element to calculate. Must be at format x,y
	 * @return Return the position it has in matrix
	 */
	public int calculatePosition(String value)
	{		
		String[] element = value.split(",");
		if (element.length < 2) 
			return -1;
		
		int row = getInteger(element[0]) + _changeStartElement;
		int col = getInteger(element[1]) + _changeStartElement;
		if (row > _rowDim || row < 1 || col > _columnDim || col < 1) 
			return -1;
		
		return (_columnDim * (row - 1)) + col + _zeroASserialStartPosition;
	}

	private int getInteger(String value)
	{
		int newValue = 0;
		if (isNumeric(value))
			newValue = Integer.parseInt(value);
		
		return newValue;
	}
	
	private boolean isNumeric(String str)
	{
	  return str.matches("-?\\d+(.\\d+)?");
	}
	
	/**
	 * Change serial start position from 1 to 0.
	 * Changed back to 1 as start position at next method call. 
	 */
	public void changeSerialStartPosition()
	{
		if (_zeroASserialStartPosition == 0)
			_zeroASserialStartPosition = -1;
		else
			_zeroASserialStartPosition = 0;
	}

	/**
	 * Increase row and column with 1 for all elements in matrix.
	 * Decreased at next method call. 
	 */
	public void increaseElements()
	{		
		if (_changeStartElement == 0)
			_changeStartElement = 1;
		else
			_changeStartElement = 0;
	}
	
}

